#include "devicemanager.h"
#include "iot_debug.h"
#include "tools/m_mutex.h"
#include "config.h"
#include "json_util.h"
#include "util_tools.h"
#include "physicallinkmanager.h"
#include "gather.h"
#include "idevice.h"
#include "crc16.h"
#include "expparser.h"
#include "string_match.h"

#include <dlfcn.h>
#include <logger.h>

#define BLE_MODEFILE "PMCMeter_MCS"
#define MAX_BLE_NUM 40

typedef std::list<WhiteDev_> WhiteList_;
std::map<uint8_t, WhiteList_> Yfzxlist_;          
std::map<uint8_t, WhiteList_> Modbuslist_;        

UseUart usrUart_;

uint8_t DevMac[240] = {0};
uint8_t Mac_Addr[200][6] = {0};
static uint8_t DevAddr = 0;
static uint8_t Blt_Num = 0;

void downLinkTest(void)
{
    DeviceManager *dev_mgr = DeviceManager::mgr();

    printf("===================\n");
    for (DeviceManager::Bays::iterator it=dev_mgr->bays_.begin();
         it!=dev_mgr->bays_.end(); it++)
    {
        DeviceManager::IDevices *devs = it->second;
        for (DeviceManager::IDevices::iterator it_dev=devs->begin();
             it_dev != devs->end(); it_dev++)
        {
            IDevice *dev = *it_dev;
            if (!dev->enabled())
                continue ;

            printf("---- dev: %s -- actived:%d ----\n", dev->devName().c_str(), dev->isActived());
            dev->dumpYX();
            dev->dumpYC();
        }
    }
}

static bool ListCompare(WhiteDev_ &p1, WhiteDev_ &p2)
{
    return p1.WhiteIdx < p2.WhiteIdx;
}

static bool Read_Mac_Num(IPhyLink *phyDev)
{
    uint8_t n;
    int count = 10;
    uint8_t sendbuf[12] = {0};
    uint8_t recvbuf[12] = {0};
    uint8_t Len = 8;
    uint16_t CRC16;

    sendbuf[0] = DevAddr;
    sendbuf[1] = 0x3;
    sendbuf[2] = 0x0;
    sendbuf[3] = 0xd;
    sendbuf[4] = 0x0;
    sendbuf[5] = 0x1;

    CRC16 = calcCRC16(sendbuf, 6);

    sendbuf[6] = CRC16 & 0xff;
    sendbuf[7] = (CRC16 >> 8) & 0xff;

    while(count-- > 0)
    {
        if (phyDev->comSettings()->dump_msg)
        {
            printf("[TX %d,%s] ", Len, logTime().c_str());
            for (int i=0; i<Len; i++) {
                printf("%02X ", sendbuf[i]);
            }
            printf("\n");
        }

        phyDev->write(sendbuf, Len);
        sleep(1);
        n = phyDev->read(recvbuf, 7, 3000);

        if (phyDev->comSettings()->dump_msg)
        {
            printf("[RX %d,%s] ", Len, logTime().c_str());
            for (int i=0; i<n; i++) {
                printf("%02X ", recvbuf[i]);
            }
            printf("\n");
        }

        if(n == 7 && recvbuf[4] == Blt_Num)
        {
            log_info("verify whitelist mac success!\n");
            return true;
        }
        else
        {
            sleep(1);
            continue;
        }
    }

    ErrCode = READ_WHITELIST_FAIL;
    log_info("verify whitelist mac failed!\n");
    log_info("%s device address %d read whitelist error\n", phyDev->comSettings()->dev_name.c_str(), DevAddr);
    sprintf(ErrMsg, "%s device address %d read whitelist error\n", phyDev->comSettings()->dev_name.c_str(), DevAddr);
    Print_err_log_msg(ErrCode, ErrMsg);
    return false;
}

static bool Write_Ble_WhiteList(int Index, int DevNum, IPhyLink *phyDev)
{
    uint8_t i, j;
    uint8_t sendbuf[512] = {0};
    uint8_t recvbuf[64] = {0};
    uint8_t Len;
    uint16_t CRC16;
    uint8_t Funcode;

    switch(Index)
    {
        case 0:
            Funcode = 0xe1;

            for(i = 0; i < DevNum; i++)
            {
                for(j = 0; j < 6; j++)
                {
                    DevMac[i * 6 + j] = Mac_Addr[i][j];
                }
            }
            break;

        case 1:
            Funcode = 0xe2;

            for(i = 0; i < DevNum; i++)
            {
                for(j = 0; j < 6; j++)
                {
                    DevMac[i * 6 + j] = Mac_Addr[40 + i][j];
                }
            }
            break;

        case 2:
            Funcode = 0xe3;

            for(i = 0; i < DevNum; i++)
            {
                for(j = 0; j < 6; j++)
                {
                    DevMac[i * 6 + j] = Mac_Addr[80 + i][j];
                }
            }
            break;

        case 3:
            Funcode = 0xe4;

            for(i = 0; i < DevNum; i++)
            {
                for(j = 0; j < 6; j++)
                {
                    DevMac[i * 6 + j] = Mac_Addr[120 + i][j];
                }
            }
            break;

        case 4:
            Funcode = 0xe5;

            for(i = 0; i < DevNum; i++)
            {
                for(j = 0; j < 6; j++)
                {
                    DevMac[i * 6 + j] = Mac_Addr[160 + i][j];
                }
            }
            break;

        default :
            break;
    }

    sendbuf[0] = DevAddr;
    sendbuf[1] = 0x10;
    sendbuf[2] = 0x55;
    sendbuf[3] = 0xf0;
    sendbuf[4] = 0x0;
    sendbuf[5] = DevNum * 3 + 1;
    sendbuf[6] = DevNum * 6 + 2;
    sendbuf[7] = Funcode;
    sendbuf[8] = DevNum;

    for(i = 0; i < DevNum * 6; i++)
    {
        sendbuf[9 + i] = DevMac[i];
    }

    Len = DevNum * 6 + 9;
    CRC16 = calcCRC16(sendbuf, Len);

    sendbuf[Len] = CRC16 & 0xff;
    sendbuf[Len + 1] = (CRC16 >> 8) & 0xff;

    if (phyDev->comSettings()->dump_msg)
    {
        printf("[TX %d,%s] ", Len + 2, logTime().c_str());
        for (int i=0; i<(Len + 2); i++) {
            printf("%02X ", sendbuf[i]);
        }
        printf("\n");
    }

    if (0 != phyDev->write(sendbuf, Len + 2))
    {
        sleep(2);
        if ((Len == phyDev->read(recvbuf, 9, 3000)) != 0)
        {
            if (phyDev->comSettings()->dump_msg)
            {
                printf("[RX %d,%s] ", Len, logTime().c_str());
                for (int i=0; i<Len; i++)
                {
                    printf("%02X ", recvbuf[i]);
                }
                printf("\n");
            }
            log_info("write whitelist mac success!\n");
            return true;
        }
        else
        {
            if (phyDev->comSettings()->dump_msg)
            {
                printf("[RX %d,%s] ", Len, logTime().c_str());
                for (int i=0; i<Len; i++)
                {
                    printf("%02X ", recvbuf[i]);
                }
                printf("\n");
            }
            log_info("write whitelist mac failed!\n");
        }
    }
    else
    {
        log_info("write whitelist mac failed!\n");
    }
    return false;

}

static bool Write_Modbus_WhiteList(WriteDev_ WriteDev, IPhyLink *phyDev)
{
    uint8_t i, j;
    uint8_t sendbuf[256] = {0};
    uint8_t recvbuf[64] = {0};
    uint8_t Len;
    uint16_t CRC16;

    sendbuf[0] = WriteDev.Addr;
    sendbuf[1] = WriteDev.WriteFunCode;
    sendbuf[2] = (WriteDev.RegStartAddr >> 8) & 0xff;
    sendbuf[3] = WriteDev.RegStartAddr & 0xff;
    sendbuf[4] = (WriteDev.RegNum >> 8) & 0xff;
    sendbuf[5] = WriteDev.RegNum & 0xff;
    sendbuf[6] = WriteDev.RegNum * 2;

    for(i = 0; i < WriteDev.RegNum * 2; i++)
    {
        sendbuf[7 + i] = WriteDev.SendBuf[i];
    }

    Len = WriteDev.RegNum * 2 + 7;
    CRC16 = calcCRC16(sendbuf, Len);

    sendbuf[Len] = CRC16 & 0xff;
    sendbuf[Len + 1] = (CRC16 >> 8) & 0xff;

    if (phyDev->comSettings()->dump_msg)
    {
        printf("[TX %d,%s] ", Len + 2, logTime().c_str());
        for (int i=0; i<(Len + 2); i++) {
            printf("%02X ", sendbuf[i]);
        }
        printf("\n");
    }

    if (0 != phyDev->write(sendbuf, Len + 2))
    {
        sleep(2);
        if ((Len = phyDev->read(recvbuf, 8, 3000)) != 0)
        {
            if (phyDev->comSettings()->dump_msg)
            {
                printf("[RX %d,%s] ", Len, logTime().c_str());
                for (int i=0; i<Len; i++)
                {
                    printf("%02X ", recvbuf[i]);
                }
                printf("\n");
            }

            log_info("write whitelist mac success!\n");
            return true;
        }
        else
        {
            if (phyDev->comSettings()->dump_msg)
            {
                printf("[RX %d,%s] ", Len, logTime().c_str());
                for (int i=0; i<Len; i++)
                {
                    printf("%02X ", recvbuf[i]);
                }
                printf("\n");
            }
            log_info("write whitelist mac failed!\n");
        }
    }
    else
    {
        log_info("write whitelist mac failed!\n");
    }
    return false;
}

static bool Read_Modbus_WhiteList(WriteDev_ WriteDev, IPhyLink *phyDev)
{
    uint8_t i, j;
    uint8_t sendbuf[256] = {0};
    uint8_t recvbuf[256] = {0};
    uint8_t Len;
    uint16_t CRC16;

    sendbuf[0] = WriteDev.Addr;
    sendbuf[1] = WriteDev.ReadFunCode;
    sendbuf[2] = (WriteDev.RegStartAddr >> 8) & 0xff;
    sendbuf[3] = WriteDev.RegStartAddr & 0xff;
    sendbuf[4] = (WriteDev.RegNum >> 8) & 0xff;
    sendbuf[5] = WriteDev.RegNum & 0xff;

    Len = 6;
    CRC16 = calcCRC16(sendbuf, Len);

    sendbuf[Len] = CRC16 & 0xff;
    sendbuf[Len + 1] = (CRC16 >> 8) & 0xff;

    if (phyDev->comSettings()->dump_msg)
    {
        printf("[TX %d,%s] ", Len + 2, logTime().c_str());
        for (int i=0; i<(Len + 2); i++) {
            printf("%02X ", sendbuf[i]);
        }
        printf("\n");
    }

    if (0 != phyDev->write(sendbuf, Len + 2))
    {
        sleep(1);
        Len = phyDev->read(recvbuf, WriteDev.RegNum * 2 + 5, 3000);

        if (phyDev->comSettings()->dump_msg)
        {
            printf("[RX %d,%s] ", Len, logTime().c_str());
            for (int i=0; i<Len; i++)
            {
                printf("%02X ", recvbuf[i]);
            }
            printf("\n");
        }

        for(i = 0; i < WriteDev.RegNum * 2; i++)
        {
            if (recvbuf[3 + i] != WriteDev.SendBuf[i])
            {
                ErrCode = READ_WHITELIST_FAIL;
                log_info("verify whitelist mac failed!\n");
                log_info("%s device address %d read whitelist error\n", phyDev->comSettings()->dev_name.c_str(), WriteDev.Addr);
                sprintf(ErrMsg, "%s device address %d read whitelist error\n", phyDev->comSettings()->dev_name.c_str(), WriteDev.Addr);
                Print_err_log_msg(ErrCode, ErrMsg);
                return false;
            }
        }
        log_info("verify whitelist mac success!\n");
    }
    else
    {
        log_info("verify whitelist mac failed!\n");
    }
    return true;
}

static bool Write_WhiteList(uint8_t UartIndex)
{
    uint8_t i, j;
    bool    ret = true;
    uint8_t offset = 0;
    uint8_t PacketNum;
    char str1[3] = {0};
    IPhyLink *phylink_ = nullptr;

    phylink_ = PhysicalLinkManager::mgr()->getDevice(UartIndex);
    if(phylink_)
    {
        if(Yfzxlist_.size() > 0)
        {
            for (auto it = Yfzxlist_.begin(); it != Yfzxlist_.end(); it++)
            {
                DevAddr = it->first;
                it->second.sort(ListCompare);

                for (auto its = it->second.begin(); its != it->second.end(); ++its)
                {
                    std::string SerialNumber = its->SerialNumber;
                    if(SerialNumber.size() != 12)
                    {
                        log_info("devid :%d, SerialNumber %s size :%d\n", its->WhiteIdx, SerialNumber.c_str(), SerialNumber.size());
                        sprintf(ErrMsg, "devid :%d, SerialNumber %s size :%d\n", its->WhiteIdx, SerialNumber.c_str(), SerialNumber.size());
                        ErrCode = SERIALNUMBER_SIZE_FAILE;
                                    Print_err_log_msg(ErrCode, ErrMsg);
                        return false;
                    }

                    for(i = 0; i < 6; i++)
                    {
                        SerialNumber.copy(str1, 2, i * 2);
                        Mac_Addr[its->WhiteIdx][i] = strtoul(str1, 0, 16);
                    }
                }

                Blt_Num =  it->second.rbegin()->WhiteIdx + 1;

                PacketNum = Blt_Num / MAX_BLE_NUM;

                if(Blt_Num % MAX_BLE_NUM != 0)
                {
                    PacketNum++;
                }

                //写Mac地址
                for(i = 0; i < PacketNum - 1; i++)
                {
                    if (false == Write_Ble_WhiteList(i, MAX_BLE_NUM, phylink_))
                    {
                        ret = false;
                        goto write_white_end;
                    }
                    sleep(2);
                }

                if (false == Write_Ble_WhiteList(i, Blt_Num - MAX_BLE_NUM * i, phylink_))
                {
                    ret = false;
                    goto write_white_end;
                }
                sleep(2);
                //写完后读取Mac数量,判断是否真正写入成功
                ret = Read_Mac_Num(phylink_);
                if (ret != true)
                {
                    goto write_white_end;
                }
            }

            Yfzxlist_.clear();
        }

        if (Modbuslist_.size() > 0)
        {
            //标准modbus规约写白名单
            uint16_t RegNum;
            WriteDev_ TempDev;
            std::list<uint16_t> RegAddr;
            std::map<uint8_t, std::string> SerialNumberlist_;

            for (auto it = Modbuslist_.begin(); it != Modbuslist_.end(); ++it)
            {
                TempDev.Addr = it->first;
                memset(TempDev.SendBuf, 0x0, 256);

                for (auto its = it->second.begin(); its != it->second.end(); ++its)
                {
                    TempDev.ReadFunCode = its->ReadFunCode;
                    TempDev.WriteFunCode = its->WriteFunCode;
                    RegAddr.push_back(its->RegStartAddr);
                    SerialNumberlist_[its->WhiteIdx] = its->SerialNumber;
                    RegNum = its->RegNum;
                }

                //提取寄存器地址
                RegAddr.sort();

                TempDev.RegStartAddr = RegAddr.front();

                //提取数据项
                for (auto its = SerialNumberlist_.begin(); its != SerialNumberlist_.end(); ++its)
                {
                    offset = (its->first - SerialNumberlist_.begin()->first) * RegNum;
                    for (i = 0; i < its->second.size() / 2; i++)
                    {
                        its->second.copy(str1, 2, i * 2);
                        TempDev.SendBuf[offset + i] = strtoul(str1, 0, 16);
                    }
                }

                auto map_at = SerialNumberlist_.rbegin();
                TempDev.RegNum = (map_at->first - SerialNumberlist_.begin()->first + 1) * RegNum / 2;

                if (false == Write_Modbus_WhiteList(TempDev, phylink_))
                {
                    ret = false;
                    goto write_white_end;
                }
                sleep(2);
                ret = Read_Modbus_WhiteList(TempDev, phylink_);
                if (ret != true)
                {
                    goto write_white_end;
                }

                offset = 0;
                RegAddr.clear();
            }

            Modbuslist_.clear();
        }
    }
write_white_end:
    return ret;
}

DeviceManager::~DeviceManager()
{
    stopGather();
    for (Gathers::iterator it=gathers_.begin(); it!=gathers_.end(); ++it)
    {
        if (it->second)
            delete it->second;
    }

    gathers_.clear();

    for (Bays::iterator it_bay=bays_.begin(); it_bay!=bays_.end(); ++it_bay)
    {
        IDevices *devs = it_bay->second;
        for (IDevices::iterator it=devs->begin(); it!=devs->end(); ++it)
        {
            if (*it)
            {
                delete *it;
            }
        }

        delete devs;
    }

    for (dl_infos::iterator it=dl_infos_.begin(); it!= dl_infos_.end(); ++it)
    {
        if (it->second.dp)
            dlclose(it->second.dp);
    }
}

DeviceManager *DeviceManager::mgr()
{
    static DeviceManager inst;
    return &inst;
}

IDevice *DeviceManager::device(uint16_t bay_id, uint16_t dev_id, int dev_type)
{
    if (bays_.find(bay_id) != bays_.end())
    {
        IDevices * devices = bays_[bay_id];
        if (devices)
        {
            for (IDevices::iterator it=devices->begin(); it!=devices->end(); ++it)
            {
                if (dev_type == 0 && (*it)->devId() == dev_id)
                    return *it;
            }
        }
    }

    return nullptr;
}

DeviceManager::IDevices *DeviceManager::devices(uint16_t bay_id)
{
    if (bays_.find(bay_id) != bays_.end())
    {
        return bays_[bay_id];
    }

    return nullptr;
}

uint16_t DeviceManager::maxDevId(uint16_t bay_id, int dev_type)
{
    uint16_t maxId = 0;
    IDevices *devs = devices(bay_id);
    if (devs)
    {
        for (auto dev = devs->begin(); dev != devs->end(); ++dev)
        {
            if (dev_type == 0 && (*dev)->devId() > maxId)
                maxId  = (*dev)->devId();
        }
    }
    return maxId;
}

//名  称: loadDevice
//描  述: 加载全部的设备
//参  数: void
//返回值: int
//        0 加载成功
//       -1 没有成功加载到设备
//       -2 解析文件失败,格式错误
//备  注: 无
int DeviceManager::loadDevice()
{
    char * content = NULL;
    cJSON *root = NULL;
    bool rc;
    {
        //加载本地工程设备
        content = readFile(DEVICEMODEL_PATH "DeviceList.json");
        if (!content)
        {
            ErrCode = OPEN_DEVLIST_FAIL;
            Print_err_log(ErrCode);
            return -2;
        }

        root = cJSON_Parse(content);
        cJSON *js = nullptr;
        rc = false;
        if (!root)
        {
            ErrCode = PARSE_DEVLIST_FAIL;
            Print_err_log(ErrCode);
            goto error;
        }

        js = cJSON_GetObjectItem(root, "ComList");
        if (js && js->type == cJSON_Array)
        {
            int item = 0;
            do
            {
                cJSON* arrItem = cJSON_GetArrayItem(js, item);
                if (arrItem)
                {
                    item++;
                    if (!loadBay(arrItem))
                    {
                        goto error;
                    }
                }
                else
                    break;
            } while(true);
        }
        freeData(content);
        content = NULL;
        cJSON_Delete(root);
        root = NULL;
    }

    for (Bays::iterator bays_it = bays_.begin();
         bays_it != bays_.end();
         ++bays_it)
    {
        IDevices *devs = bays_it->second;
        std::map<uint32_t, uint32_t> repeatIds;

        //检测设备ID是否重复
        for (IDevices::iterator it = devs->begin();
             it != devs->end();
             ++it)
        {
            uint32_t dev_id = (*it)->devId();
            IDevices::iterator it2 = it;
            it2++;
            for (; it2!=devs->end(); it2++)
            {
                if (dev_id == (*it2)->devId())
                {
                    if (repeatIds.find(dev_id) == repeatIds.end())
                    {
                        log_info("%s dev_id :%d repeat!\n", (*it2)->com()->UartName(), dev_id);
                        sprintf(ErrMsg, "%s dev_id :%d repeat!\n", (*it2)->com()->UartName(), dev_id);
                        ErrCode = DEVLIST_DEVID_REPEAT;
                        Print_err_log_msg(ErrCode, ErrMsg);
                        goto error;
                    }

                    repeatIds[dev_id] += 1;
                    break;
                }
            }
        }
    }

    //填充采集map容器gathers_
    ids_.reserve(bays_.size());
    for (Bays::iterator bays_it = bays_.begin();
         bays_it != bays_.end();
         ++bays_it)
    {
        ids_.push_back(bays_it->first);
        IDevices *devs = bays_it->second;
        for (auto it = devs->begin();
             it != devs->end();
             ++it)
        {
            Gather *gather = findGather((*it)->com()->devName());
            if (gather == nullptr)
            {
                gather = new Gather();
                gathers_[(*it)->com()->devName()] = gather;
            }

            gather->addDevice(*it);
        }
    }

    //串口相关信息
    for (Bays::iterator bays_it = bays_.begin();
         bays_it != bays_.end();
         ++bays_it)
    {
        IPhyLink *Iphylink_ = PhysicalLinkManager::mgr()->getDevice(bays_it->first);
        if (Iphylink_)
        {
            ComSettings *com_ = Iphylink_->comSettings();

            if(com_->dev_name.find("/dev/") != std::string::npos)
            {
                usrUart_.push_back(com_);
            }
        }
        else{}
    }
    rc = true;
error:
    if (content)
        freeData(content);
    if (root)
        cJSON_Delete(root);

    if (rc) {
        if (dl_infos_.size() > 0)
        {
            return 0;
        }
        else
        {
            ErrCode = DEVLIST_IS_NULL;
            Print_err_log(ErrCode);
            return -1;
        }
    }
    else{}
    return -2;
}

void DeviceManager::setDebugDevice(int com_index, int dev_index)
{
    if (com_index == -1)
        return ;

    for (Bays::iterator bays_it=bays_.begin(); bays_it!=bays_.end(); ++bays_it)
    {
        IDevices *devs = bays_it->second;
        for (IDevices::iterator it=devs->begin(); it!=devs->end(); ++it)
        {
            (*it)->setEnable(false);
        }
    }

    uint16_t bay_id = static_cast<uint16_t>(com_index);
    if (dev_index == -1)
    {
        if (bays_.find(bay_id) != bays_.end())
        {
            IDevices * devices = bays_[bay_id];
            if (devices)
            {
                for (IDevices::iterator it=devices->begin(); it!=devices->end(); ++it)
                {
                    (*it)->setEnable(true);
                }
            }
        }
        else
        {
            printf("通信端口(%s)未找到设备\n", PhysicalLinkManager::mgr()->devName(bay_id));
        }
    }
    else
    {
        IDevice *dev = device(bay_id, static_cast<uint16_t>(dev_index));
        if (dev)
        {
            dev->setEnable(true);
        }
        else
        {
            printf("通信端口(%s)下未找到设备ID为%d的子设备\n", PhysicalLinkManager::mgr()->devName(bay_id), dev_index);
        }
    }
}

void DeviceManager::ShowDeviceList(int com_index)
{
    if (com_index == -1)
    {
        for (Bays::iterator bays_it = bays_.begin(); bays_it != bays_.end(); ++bays_it)
        {
            IDevices *devs = bays_it->second;

            printf("%s device List:\n", PhysicalLinkManager::mgr()->getPortName(PhysicalLinkManager::mgr()->devName(bays_it->first)));
            for (IDevices::iterator it = devs->begin(); it != devs->end(); ++it)
            {
                printf("desc    :%s\n", (*it)->devInfo()->desc.c_str());
                printf("addr    :%s\n", (*it)->devInfo()->addr.c_str());
                printf("dev_id  :%s\n", (*it)->devInfo()->dev_id.c_str());
                printf("model   :%s\n", (*it)->devInfo()->model.c_str());
                printf("------------------------------------\n");
            }
        }
    }
    else
    {
        uint16_t bay_id = static_cast<uint16_t>(com_index);

        if (bays_.find(bay_id) != bays_.end())
        {
            IDevices * devices = bays_[bay_id];
            if (devices)
            {
                printf("%s device List:\n", PhysicalLinkManager::mgr()->devName(bay_id));
                for (IDevices::iterator it=devices->begin(); it!=devices->end(); ++it)
                {
                    printf("desc    :%s\n", (*it)->devInfo()->desc.c_str());
                    printf("addr    :%s\n", (*it)->devInfo()->addr.c_str());
                    printf("dev_id  :%s\n", (*it)->devInfo()->dev_id.c_str());
                    printf("model   :%s\n", (*it)->devInfo()->model.c_str());
                    printf("------------------------------------\n");
                }
            }
        }
        else
        {
            printf("%s not config device!\n", PhysicalLinkManager::mgr()->devName(com_index));
        }
    }
}

void DeviceManager::startGather()
{
    for (dl_infos::iterator it=dl_infos_.begin(); it!= dl_infos_.end(); ++it)
    {
        if (it->second.start)
            it->second.start();
    }

    std::list<MSem*> sems;
    for (Gathers::iterator it=gathers_.begin(); it!=gathers_.end(); ++it)
    {
        it->second->startGather();
    }
}

void DeviceManager::stopGather()
{
    for (Gathers::iterator it=gathers_.begin(); it!=gathers_.end(); ++it)
    {
        it->second->stopGather();
    }
}

void DeviceManager::getModelNames(std::list<std::string> &model_names)
{
    for (auto it=bays_.begin(); it!=bays_.end(); ++it)
    {
        IDevices *devs = it->second;
        for (auto it_dev=devs->begin(); it_dev!=devs->end(); ++it_dev)
        {
            const char * name = (*it_dev)->modelName();
            bool contained = false;

            for (auto m=model_names.begin(); m!=model_names.end(); ++m)
            {
                if (m->compare(name) == 0)
                {
                    contained = true;
                    break;
                }
            }

            if (!contained)
                model_names.push_back(name);
        }
    }
}

void DeviceManager::getDevices(const std::string &model_name, DeviceManager::IDevices &devs)
{
    devs.clear();
    if (model_name.empty())
    {
        for (auto it=bays_.begin(); it!=bays_.end(); ++it)
        {
            const IDevices *d = it->second;
            for (auto it_dev=d->begin(); it_dev!=d->end(); ++it_dev)
                devs.push_back(*it_dev);
        }
    }
    else
    {
        for (auto it=bays_.begin(); it!=bays_.end(); ++it)
        {
            const IDevices *d = it->second;
            for (auto it_dev=d->begin(); it_dev!=d->end(); ++it_dev)
            {
                const char * name = (*it_dev)->modelName();
                if (model_name.compare(name) == 0)
                    devs.push_back(*it_dev);
            }
        }
    }
}

DeviceManager::DeviceManager()
{

}

Gather *DeviceManager::findGather(const char *link_name)
{
    Gathers::iterator it = gathers_.find(link_name);

    if (it!=gathers_.end())
    {
        return it->second;
    }

    return nullptr;
}

bool DeviceManager::loadBay(cJSON *root, int type)
{
    bool enable = true;
    bool ret;
    cJSON_GetInt(root, "Enable", enable);
    if (!enable)
    {
        return true;
    }

    uint16_t bay_id = 0;
    uint16_t uart_index = 0xFFFF;
    uint16_t dev_id_offset = 0;
    std::string uart_name("");
    cJSON *js = nullptr;
    IDevices *devs = nullptr;

    if (type == 0)
    {
        if ( cJSON_GetInt(root, "ComIndex", uart_index) )
        {
            if (uart_index >= PhysicalLinkManager::mgr()->devNum())
            {
                sprintf(ErrMsg, "index %d beyond comsetting max index.\n", uart_index);
                log_info("%s", ErrMsg);
                ErrCode = DEVLIST_INDEX_FAIL;
                Print_err_log_msg(ErrCode, ErrMsg);
                goto cleanup;
            }
        }
    }
    else
    {
        if ( cJSON_GetString(root, "ComName", uart_name) )
        {
            uart_index = PhysicalLinkManager::mgr()->getIndexByPort(uart_name.c_str());
            if (uart_index >= PhysicalLinkManager::mgr()->devNum())
            {
                sprintf(ErrMsg, "index %d beyond comsetting max index.\n", uart_index);
                log_info("%s", ErrMsg);
                ErrCode = DEVLIST_INDEX_FAIL;
                Print_err_log_msg(ErrCode, ErrMsg);
                goto cleanup;
            }
        }
        else
        {

        }
    }

    bay_id = uart_index;
    if (bays_.find(bay_id) != bays_.end() && type == 0)
    {
        sprintf(ErrMsg, "comsetting repeat index %d\n", uart_index);
        log_info("%s", ErrMsg);
        ErrCode = DEVLIST_INDEX_FAIL;
        Print_err_log_msg(ErrCode, ErrMsg);
        goto cleanup;
    }

    devs = devices(bay_id);
    if (!devs)
    {
        devs = new IDevices;
        devs->clear();
        bays_[bay_id] = devs;
        dev_id_offset = 0;
    }
    else
    {
        dev_id_offset = maxDevId(bay_id);
    }

    js = cJSON_GetObjectItem(root, "DeviceList");
    if (js && js->type == cJSON_Array)
    {
        int item = 0;
        do
        {
            cJSON* arrItem = cJSON_GetArrayItem(js, item);
            if (arrItem)
            {
                item++;
                bool enable = true;
                if ( cJSON_GetInt(arrItem, "Enable", enable) && !enable )
                {
                    std::string model_file;
                    cJSON_GetString(arrItem, "DeviceModel", model_file);
                    continue;
                }

                std::string model_file;
                if (!cJSON_GetString(arrItem, "DeviceModel", model_file))
                {
                    goto cleanup;
                }

                if (!loadModelFile(arrItem, model_file.c_str(), uart_index, bay_id, devs, type, dev_id_offset))
                {
                    goto cleanup;
                }
            }
            else
                break;
        } while(true);
    }

    ret = true;

    if (!Write_WhiteList(uart_index))
    {
        log_info("write white list failed, err code :%d\n", ErrCode);
    }

    return ret;
cleanup:
    return false;
}

bool DeviceManager::loadModelFile(cJSON *root, const char *model_file,
                                  int32_t uart_index, uint16_t bay_id, IDevices *devs, int type, uint16_t dev_id_offset)
{
    bool rc = false;

    cJSON *root_model = nullptr;
    std::string protocol("");

    std::string file("");
    if (type == 0)
        file = DEVICEMODEL_PATH;

    file += model_file;
    file += ".json";
    char * content = readFile(file.c_str());

    if (NULL == content)
    {
        sprintf(ErrMsg, "mode file:%s not exist\n", file.c_str());
        log_info("%s", ErrMsg);
        ErrCode = MODE_FILE_NOTEXIST;
        Print_err_log_msg(ErrCode, ErrMsg);
        goto cleanup;
    }

    root_model = cJSON_Parse(content);
    if (!root_model)
    {
        sprintf(ErrMsg, "parse mode file:%s faile\n", file.c_str());
        log_info("%s", ErrMsg);
        ErrCode = PARSE_MODE_FAIL;
        Print_err_log_msg(ErrCode, ErrMsg);
        goto cleanup;
    }

    if (!cJSON_GetString(root_model, "Protocol", protocol))
    {
        protocol = PRO_MODBUS;
    }

    std::transform(protocol.begin(), protocol.end(), protocol.begin(), ::tolower);

    {
        IDevice *dev = genDevice(root, root_model, model_file, uart_index, bay_id, type, dev_id_offset, protocol);
        if (!dev)
        {
            goto cleanup;
        }

        devs->push_back(dev);
    }

    rc = true;
cleanup:
    if (content)
        freeData(content);
    if (root_model)
        cJSON_Delete(root_model);

    return rc;
}

IDevice *DeviceManager::genDevice(
                cJSON *root,
                cJSON *root_model,
                const char * model_file,
                int32_t uart_index,
                uint16_t bay_id,
                int      type,
                uint16_t dev_id_offset,
                const std::string &protocol)
{
    int ret;
    cJSON *js = nullptr, *js_sub = nullptr;
    IPhyLink *phylink = nullptr;
    IDevice *dev = nullptr;
    uint8_t  index = static_cast<uint8_t>(uart_index);
    uint16_t dev_id = 0xFFFF;
    uint64_t  addr = 0;
    cJSON *arr_params = cJSON_GetObjectItem(root, "Params");
    std::string dll("");
    std::string SerialNumber;
    std::string RegStartAddrPLC;
    dl_info dl;
    WhiteDev_ WhiteDev;

    if (!parseDevInfo(root, bay_id, dev_id, addr, index, protocol))
        goto cleanup;
    dev_id += dev_id_offset;

    phylink = PhysicalLinkManager::mgr()->getDevice(index);

    if (protocol.find("modbus") != std::string::npos)
    {
        dll = PRO_MODBUS;
    }
    else if (protocol.find("iec") != std::string::npos)
    {
        dll = PRO_IEC101;
    }
    else
    {
        ErrCode = MODE_PROTOCOL_ERROR;
        sprintf(ErrMsg, "model file %s 协议解析失败\n", model_file);
        Print_err_log_msg(ErrCode, ErrMsg);
        goto cleanup;
    }

    dll.insert(0, "./plugin/lib");
    dll += ".so";

    dl = loadDll(dll);
    if (dl.dp == nullptr)
    {
        ErrCode = MODE_PROTOCOL_ERROR;
        sprintf(ErrMsg, "model file %s 协议解析失败\n", model_file);
        Print_err_log_msg(ErrCode, ErrMsg);
        goto cleanup;
    }

    dev = dl.createDevice(protocol.c_str(), bay_id, dev_id, phylink);
    if (dev == nullptr)
    {
        ErrCode = MODE_PROTOCOL_ERROR;
        sprintf(ErrMsg, "model file %s 协议解析失败\n", model_file);
        Print_err_log_msg(ErrCode, ErrMsg);
        goto cleanup;
    }

    dev->setProcotol(protocol);

    dev->setPhylinkMgr(PhysicalLinkManager::mgr());

    if (cJSON_GetInt(root, "WhiteListIdx", dev->WhiteIdx))
    {
        //使用新的配置
        if (!cJSON_GetString(root, "SerialNumber", SerialNumber))
        {
            //未配置SerialNumber
            log_info("%s device address %d SerialNumber not config\n", phylink->comSettings()->dev_name.c_str(), addr);
            sprintf(ErrMsg, "%s device address %d SerialNumber not config\n", phylink->comSettings()->dev_name.c_str(), addr);
            ErrCode = NOT_CONFIG_SERIALNUMBER;
            Print_err_log_msg(ErrCode, ErrMsg);
            return nullptr;
        }
        else
        {
            //已配置SerialNumber
            js = cJSON_GetObjectItem(root_model, "WhiteList");
            if (js)
            {
                WhiteDev.UartIndex = uart_index;
                cJSON_GetString(js, "Protocol", WhiteDev.Protocol);
                if (strcmp(WhiteDev.Protocol.c_str(), "modbus_yfzx") == 0)
                {
                    if (!cJSON_GetInt(js, "DevNum", WhiteDev.DevNum))
                    {
                        WhiteDev.DevNum = 40;
                    }

                    if(dev_id >= 200 || dev->WhiteIdx >= 201)
                    {
                        log_info("ble DevId :%d error\n", dev_id);
                        return nullptr;
                    }

                    WhiteDev.SerialNumber = SerialNumber;
                    WhiteDev.WhiteIdx        =    dev->WhiteIdx;
                    Yfzxlist_[addr].push_back(WhiteDev);
                }
                else if (strcmp(WhiteDev.Protocol.c_str(), "modbus") == 0)
                {
                    //标准modbus
                    WhiteDev.SerialNumber = SerialNumber;
                    WhiteDev.WhiteIdx = dev->WhiteIdx;

                    if (!cJSON_GetInt(js, "DevNum", WhiteDev.DevNum))
                    {
                        WhiteDev.DevNum = 32;
                    }

                    js_sub = cJSON_GetObjectItem(js, "modbus");
                    if(js_sub)
                    {
                        cJSON_GetInt(js_sub, "ReadFunCode", WhiteDev.ReadFunCode);
                        cJSON_GetInt(js_sub, "WriteFunCode", WhiteDev.WriteFunCode);
                        cJSON_GetInt(js_sub, "RegNum", WhiteDev.RegNum);

                        if (cJSON_GetString(js_sub, "RegStartAddrPLC", RegStartAddrPLC))
                        {
                            RegStartAddrPLC.replace(0, 3, i32toa(dev->WhiteIdx));
                            WhiteDev.RegStartAddr = atoi(ExpParser::calcExp(RegStartAddrPLC).c_str());
                        }
                    }

                    Modbuslist_[addr].push_back(WhiteDev);
                }
            }
        }
    }
    else
    {
        if (cJSON_GetString(root, "SerialNumber", SerialNumber) && strstr(model_file, BLE_MODEFILE))
        {
            if(dev_id >= 200)
            {
                log_info("ble DevId :%d error\n", dev_id);
                return nullptr;
            }

            WhiteDev.UartIndex = uart_index;
            WhiteDev.SerialNumber = SerialNumber;
            WhiteDev.WhiteIdx         =     dev_id - 1;
            Yfzxlist_[addr].push_back(WhiteDev);
        }
    }

    ret = dev->genDevice(root, root_model, model_file, addr, arr_params);
    if (ret != true)
    {
        ErrCode = ret;
        switch (ErrCode)
        {
            case PARSE_MODE_FAIL:
                sprintf(ErrMsg, "parse model file %s failed\n", model_file);
                break;

            case MODE_TYPE_ERROR:
                sprintf(ErrMsg, "model file %s type定义错误\n", model_file);
                break;

            case MODE_REGNAME_ERROR:
                sprintf(ErrMsg, "model file %s Regname定义错误\n", model_file);
                break;

            case MODE_REGSIZE_ERROR:
                sprintf(ErrMsg, "model file %s 寄存器数量错误\n", model_file);
                break;

            default:
                sprintf(ErrMsg, "未知错误\n", model_file);
                break;
        }

        Print_err_log_msg(ErrCode, ErrMsg);
        delete dev;
        goto cleanup;
    }

    return dev;

cleanup:
    log_info("load model(%s) failed.\n", model_file);
    return nullptr;
}

#include <sstream>
bool DeviceManager::parseDevInfo(cJSON *root, uint16_t /*bay_id*/, uint16_t &dev_id, uint64_t &dev_addr, uint8_t &index, const std::string& protocol)
{
    bool rc = false;

    cJSON_GetInt(root, "DevId", dev_id);

    std::string addr_str = "";
    if (cJSON_GetString(root, "DevAddr_hex", addr_str))
    {
        std::istringstream ss(addr_str);
        ss >> std::hex >> dev_addr;
    }
    else if (cJSON_GetString(root, "DevAddr", addr_str))
    {
        std::istringstream ss(addr_str);
        ss >> std::dec >> dev_addr;
    }
    else
    {
        log_info("Parse device info failed due to 'DevAddr' not found.\n");
        goto cleanup;
    }

    if (cJSON_GetInt(root, "ComIndex", index))
    {
        if (index >= PhysicalLinkManager::mgr()->devNum())
        {
            log_info("Parse device info failed due to 'ComIndex' not found.\n");
            goto cleanup;
        }
    }

    rc = true;
cleanup:
    return rc;
}

DeviceManager::dl_info DeviceManager::loadDll(const std::string &dll)
{
    dl_infos::iterator it = dl_infos_.begin();
    dl_info dl;

    dl.dp = nullptr;

    while (it != dl_infos_.end())
    {
        if (it->first.compare(dll) == 0)
            break;
        it++;
    }

    if (it == dl_infos_.end())
    {
        void *dp = dlopen(dll.c_str(), RTLD_LAZY);
        if (dp == nullptr)
        {
            log_info("dlopen %s failed: %s\n", dll.c_str(), dlerror());
            goto exitCoe;
        }

        dl.createDevice = reinterpret_cast<PFN_CreateDevice>(dlsym(dp, "CreateDevice"));
        dl.releaseDevice = reinterpret_cast<PFN_ReleaseDevice>(dlsym(dp, "ReleaseDevice"));
        dl.getVersion = reinterpret_cast<PFN_GetVersion>(dlsym(dp, "GetVersion"));
        dl.start = reinterpret_cast<PFN_Start>(dlsym(dp, "Start"));
        dl.setHandler = reinterpret_cast<PFN_SetHandler>(dlsym(dp, "setHandler"));
        if (dl.createDevice && dl.releaseDevice && dl.getVersion)
        {
            dl.dp = dp;
            log_info("load dll:%s with %s\n", dll.c_str(), dl.getVersion());
        }
        else
        {
            dlclose(dp);
            goto exitCoe;
        }

        dl_infos_[dll] = dl;
    }
    else
    {
        dl = it->second;
    }

exitCoe:
    return dl;
}
